package game.groves.hollow;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;


public class GameView extends SurfaceView implements SurfaceHolder.Callback {

	private MainThread thread;
	private static final String TAG = GameView.class.getSimpleName();
	private Player player;
	private List<Block> blocks;
	private List<Parallax> parallaxes;
	private static final int BLOCK_SPEED = 2;
	private double startX;
	private double startY;
	private static final int BLOCK_HEIGHT = 32;
	private static final int BLOCK_WIDTH = 32;
	private char[][] level;
	private int screenHeight;
	private int screenWidth;
	private int leftMostBlock;
	private int nextColumn;
	private Point startPoint;
	private Point endPoint;
	private Point currPoint;
	private Paint fpsPaint;
	
	public GameView(Context context) {
		super(context);
		// adding the callback (this) to the surface holder to intercept events
		getHolder().addCallback(this);
		
		fpsPaint = new Paint();
		fpsPaint.setARGB(255, 255, 255, 255);
		
		
		//Get the screen height and width
		WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
		Display display = wm.getDefaultDisplay();
		screenHeight = display.getHeight();
		screenWidth = display.getWidth();
		
		setupPlayer();
		
		thread = new MainThread(getHolder(), this);
		blocks = new ArrayList<Block>();
		parallaxes = new ArrayList<Parallax>();
		
		level = generateLevel(100, 0.15);
		
		startPoint = new Point();
		currPoint = new Point();
		endPoint = new Point();

		setupParallax();
		parseLevel();
		// make the GamePanel focusable so it can handle events
		setFocusable(true);

	}
	
	private void setupPlayer(){
		int playerX = 300;
		int playerY = 200;
		Animation walkingAnimation = new Animation(BitmapFactory.decodeResource(getResources(), R.drawable.player_walk), 6, 6);
		player = new Player(walkingAnimation, walkingAnimation,
				walkingAnimation, walkingAnimation, walkingAnimation,
				walkingAnimation, playerX, playerY, screenHeight);
	}
	
	private void setupParallax(){
		Parallax parallax2 = new Parallax(BitmapFactory.decodeResource(getResources(), R.drawable.sky), screenWidth, 4);
		parallaxes.add(parallax2);
		Parallax parallax = new Parallax(BitmapFactory.decodeResource(getResources(), R.drawable.tree), screenWidth, 3);
		parallaxes.add(parallax);

	}


	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		
		thread.setRunning(true);
		thread.start();
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		boolean retry = true;
		while (retry) {
			try {
				thread.join();
				retry = false;
			} catch (InterruptedException e) {
				// try again shutting down the thread
			}
		}
		Log.d(TAG, "Thread was shut down cleanly");

	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		if (event.getAction() == MotionEvent.ACTION_DOWN) {
			startPoint.x = (int)event.getX();
			startPoint.y = (int)event.getY();
			player.setStartPoint(startPoint);
		}
		if (event.getAction() == MotionEvent.ACTION_MOVE) {
			currPoint.x = (int)event.getX();
			currPoint.y = (int)event.getY();
			player.setCurrPoint(currPoint);
			
		}
		if (event.getAction() == MotionEvent.ACTION_UP) {
			endPoint.x = (int)event.getX();
			endPoint.y = (int)event.getY();
			player.setEndPoint(endPoint);
		}
		return true;
	}

	
	//Update all game objects
	public void update(){
		//Check if player is off screen, end game if so
		if ((player.getX() > screenWidth) || (player.getY() > screenHeight)){
		thread.setRunning(false);
		((Activity) getContext()).finish();
		}
		
		for (int i = 0; i < parallaxes.size(); i++){
			parallaxes.get(i).update();
		}
		
		for(int i = blocks.size() - 1; i >= 0; i--){
			blocks.get(i).update(BLOCK_SPEED);
			if (blocks.get(i).getX() > screenWidth){
				blocks.remove(i);
			}
		}
		leftMostBlock += BLOCK_SPEED;
		addBlocks();

		player.update(System.currentTimeMillis(), blocks);

	}
	
	// the fps to be displayed
	private String avgFps;
	public void setAvgFps(String avgFps) {
		this.avgFps = avgFps;
	}

	
	//Render all game objects
	public void render(Canvas canvas) {
		canvas.drawColor(Color.BLACK);
		
		for (int i = 0; i < parallaxes.size(); i++){
			parallaxes.get(i).draw(canvas);
		}
		
		for(Block b : blocks){
			b.draw(canvas);
		}
		player.draw(canvas);
		// display fps
		displayFps(canvas, avgFps);
	}

	private void displayFps(Canvas canvas, String fps) {
		if (canvas != null && fps != null) {
			canvas.drawText(fps, this.getWidth() - 50, 20, fpsPaint);
		}
	}
	
//---------------------------------------------------------------------------------------------
//Functions dealing with Setting up the blocks and maintaining them
//
//Set up the level and add the blocks that start on screen

	private char[][] generateLevel(int columns, double density) {

		int rows = screenHeight / BLOCK_HEIGHT;

		//Log.d(TAG, "the height of the device is " + this.getHeight());

		char[][] localLevel = new char[columns][rows];
		Random generator = new Random();
		boolean blockPlaced = false;
		//Log.d(TAG, "The size of level is" + localLevel.length + " and it has "
			//	+ rows + " rows");
		char object;
		int randNum;

		for (int x = 0; x < columns; x++) {

			//Log.d(TAG, "just inserted t" + " at index" + x + ", " + 0);

			localLevel[x][0] = 't';
			blockPlaced = true;

			for (int y = 1; y < (rows - 1); y++) {
				object = '?';
				randNum = generator.nextInt(99);
				if (randNum < (100.0 * density)) {
					if (blockPlaced) {
						object = 'm';
					} else {
						object = 't';
					}
					blockPlaced = true;
				} else {
					blockPlaced = false;
				}
				if (x != player.getX() && y != player.getY()) {
					localLevel[x][y] = object;
				}
				//Log.d(TAG, "just inserted " + object + " at index" + x + ", "
						//+ y);
			}
			if (blockPlaced) {
				localLevel[x][rows - 1] = 'm';
			} else {
				localLevel[x][rows - 1] = 't';
			}
			//Log.d(TAG, "just inserted t" + " at index" + x + ", " + (rows - 1));
		}

		return localLevel;
	}

//Add the blocks that start on screen	
	private void parseLevel() {

		int columns = (screenWidth / BLOCK_WIDTH) + 3;
		int rows = (screenHeight / BLOCK_HEIGHT);
		
		for (int x = 0; x < columns; x++) {
			for (int y = 0; y < rows; y++) {
				char c = level[x][y];
				switch (c) {
				case 't':
				//	Log.d(TAG, "Added Top Block at" + x + "," + y);
					blocks.add(new Block(screenWidth - (x * 32), y * 32, 32, 32, BitmapFactory
							.decodeResource(getResources(),
									R.drawable.dark_dirt_top)));
					break;
				case 'm':
				//	Log.d(TAG, "Added Bot Block at" + x + "," + y);
					blocks.add(new Block(screenWidth - (x * 32), y * 32, 32, 32, BitmapFactory
							.decodeResource(getResources(),
									R.drawable.dark_dirt_mid)));
					break;
				default:
					break;
				}
			}
		}
		Log.d(TAG, "The leftmost block is at " + (screenWidth - ((columns - 1) * BLOCK_WIDTH)) + " and the next column is " + columns);
		leftMostBlock = (screenWidth - ((columns - 1) * BLOCK_WIDTH));
		nextColumn = columns;
	}
	
	
	// Add a new row of blocks when needed
	private void addBlocks() {
		if ((leftMostBlock > (-1 * BLOCK_WIDTH)) && (nextColumn < level.length)) {
			int x = leftMostBlock - BLOCK_WIDTH;
			for (int y = 0; y < level[nextColumn].length; y++) {
				char c = level[nextColumn][y];
				switch (c) {
				case 't':
					// Log.d(TAG, "Added Top Block at" + x + "," + y);
					blocks.add(new Block(x, y * BLOCK_HEIGHT, BLOCK_WIDTH,
							BLOCK_HEIGHT, BitmapFactory.decodeResource(
									getResources(), R.drawable.dark_dirt_top)));
					break;
				case 'm':
					// Log.d(TAG, "Added Bot Block at" + x + "," + y);
					blocks.add(new Block(x, y * BLOCK_HEIGHT, BLOCK_WIDTH,
							BLOCK_HEIGHT, BitmapFactory.decodeResource(
									getResources(), R.drawable.dark_dirt_mid)));
					break;
				default:
					break;
				}
			}
			leftMostBlock = x;
			nextColumn++;
		}
	}

	//-----------------------------------------------------------------------------------------------------------------------------

}
